﻿using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using TimeTravel.XnaLibrary.GamePlay;

namespace TimeTravel.XnaLibrary
{
	/// <summary>
	/// Static class for parsing game settings for the TimeTravel game.
	/// </summary>
	public static class Parser
	{
		/// <summary>
		/// Parses the specified text and uses the specified ContentManager to create user-defined races.
		/// </summary>
		/// <param name="text">The text to parse.</param>
		/// <param name="content">The ContentManager used for loading unit icons.</param>
		/// <param name="iconsPerUnit">The number of icons per unit to be loaded.</param>
		public static Race[] ParseRaces(TextReader text, ContentManager content, int iconsPerUnit)
		{
			string line = text.ReadLine();
			Race[] races = new Race[2];
			races[0] = new Race();
			races[1] = new Race();
			int currentRaceIndex = -1;
			Unit currentUnit = new Unit();
			while (line != null)
			{
				if (line.StartsWith("#"))
				{
					line = text.ReadLine();
					continue;
				}
				else if (line.StartsWith("New Race"))
				{
					currentRaceIndex++;
				}
				else if (line.StartsWith("New Unit"))
				{
					if (currentUnit != null)
						currentUnit.CalculateFoodCost();
					currentUnit = new Unit();
					races[currentRaceIndex].Units.Add(currentUnit);
					if (races[currentRaceIndex].Units.Count == 1)
						currentUnit.Level = 1;
				}
				else if (line.StartsWith("IconNumber"))
				{
					line = line.Replace("IconNumber: ", "");
					string path = "Units\\" + line + "_";
					for (int i = 1; i < iconsPerUnit + 1; i++)
					{
						currentUnit.Icons.Add(content.Load<Texture2D>(path + i));
					}
					currentUnit.ActiveIcon = currentUnit.Icons[0];
				}
				else if (line.StartsWith("Name"))
				{
					line = line.Replace("Name: ", "");
					currentUnit.Name = line;
				}
				else if (line.StartsWith("GoldCost"))
				{
					currentUnit.GoldCost = Int32.Parse(line.Replace("GoldCost: ", ""));
				}
				else if (line.StartsWith("Speed"))
				{
					currentUnit.Speed = Int32.Parse(line.Replace("Speed: ", ""));
				}
				else if (line.StartsWith("Health"))
				{
					int hp = Int32.Parse(line.Replace("Health: ", ""));
					currentUnit.Health = hp;
					currentUnit.MaxHealth = hp;
				}
				else if (line.StartsWith("Damage"))
				{
					currentUnit.Damage = Int32.Parse(line.Replace("Damage: ", ""));
				}
				else if (line.StartsWith("Range"))
				{
					currentUnit.Range = Int32.Parse(line.Replace("Range: ", ""));
				}
				else if (line.StartsWith("Critical"))
				{
					currentUnit.CriticalChance = Single.Parse(line.Replace("Critical: ", ""));
				}
				else if (line.StartsWith("Dodge"))
				{
					currentUnit.DodgeChance = Single.Parse(line.Replace("Dodge: ", ""));
				}

				line = text.ReadLine();
			}

			return races;
		}
		
		/// <summary>
		/// Parses the specified text and creates an array of PriorityOrders defining an AI.
		/// </summary>
		/// <param name="text">The text to parse.</param>\
		public static PriorityOrder[] ParseAIOrders(TextReader text)
		{
			List<PriorityOrder> orders = new List<PriorityOrder>();
			string line = text.ReadLine();
			int priority = 1;
			PriorityOrderCondition condition = new PriorityOrderCondition((player) => false);
			PriorityOrderCommand command = new PriorityOrderCommand((player) => {});
			while (line != null)
			{	
				if (line.StartsWith("#"))
				{
					line = text.ReadLine();
					continue;
				}

				if (line.StartsWith("IF"))
				{
					line = line.Replace("IF", "");
					string[] orderParameters = line.Split(new string[]{ "THEN" }, StringSplitOptions.RemoveEmptyEntries);
					string conditionString = orderParameters[0].Trim().ToLower();
					string commandString = orderParameters[1].Trim().ToLower();

					if (conditionString == "true")
					{
						condition = new PriorityOrderCondition((player) => { return true; });
					}
					else if (conditionString.Contains("sleeping"))
					{
						condition = ParserSleepingCondition(conditionString);
					}
					else if (conditionString.Contains("upgrade"))
					{
						condition = ParseUpgradeCondition(conditionString);
					}
					else if (conditionString.Contains("gold"))
					{
						condition = ParseGoldCondition(conditionString);
					}

					if (commandString.Contains("attack"))
					{
						command = new PriorityOrderCommand((player) => player.Attack());
					}
					else if (commandString.Contains("build"))
					{
						commandString = commandString.Replace("build(", "");
						int rightBracketIndex = commandString.IndexOf(')');
						int unitTier = Int32.Parse(commandString.Substring(0, rightBracketIndex));
						command = new PriorityOrderCommand((player) => player.BuyUnit(unitTier));
					}
					else if (commandString.Contains("upgrade"))
					{
						commandString = commandString.Replace("upgrade(", "");
						int rightBracketIndex = commandString.IndexOf(')');
						int unitTier = Int32.Parse(commandString.Substring(0, rightBracketIndex));
						command = new PriorityOrderCommand((player) => player.UpgradeUnit(unitTier));
					}
					orders.Add(new PriorityOrder(priority, condition, command));
					priority++;
				}

				line = text.ReadLine();
			}
			return orders.ToArray();
		}

		/// <summary>
		/// Parses the specified text and creates game specific settings.  
		/// </summary>
		/// <param name="text">The text to parse.</param>
		public static GameSettings ParseGameSetings(TextReader text)
		{
			GameSettings settings = new GameSettings();
			string line = text.ReadLine();

			while (line != null)
			{
				if (line.StartsWith("#"))
				{
					line = text.ReadLine();
					continue;
				}
				else if (line.StartsWith("StartingGold"))
				{
					int gold = Int32.Parse(line.Replace("StartingGold: ", ""));
					settings.StartingGold = gold;
				}
				else if (line.StartsWith("StartingMana"))
				{
					int mana = Int32.Parse(line.Replace("StartingMana: ", ""));
					settings.StartingMana = mana;
				}
				else if (line.StartsWith("ForwardUnit"))
				{
					int manaCost = Int32.Parse(line.Replace("ForwardUnitCost: ", ""));
					settings.ForwardUnitCost = manaCost;				
				}
				else if (line.StartsWith("RewindUnit"))
				{
					int manaCost = Int32.Parse(line.Replace("RewindUnitCost: ", ""));
					settings.RewingUnitCost = manaCost;						
				}
				else if (line.StartsWith("KillEnemy"))
				{
					int manaCost = Int32.Parse(line.Replace("KillEnemyCost: ", ""));
					settings.KillEnemyCost = manaCost;
				}
				else if (line.StartsWith("Butterfly"))
				{
					int manaCost = Int32.Parse(line.Replace("ButterflyCost: ", ""));
					settings.ButterflyCost = manaCost;
				}
				else if (line.StartsWith("StartingFood"))
				{
					int startingFood = Int32.Parse(line.Replace("StartingFood: ",""));
					settings.StartingFood = startingFood;
				}
				else if (line.StartsWith("FoodPerTile"))
				{
					int foodPerTile = Int32.Parse(line.Replace("FoodPerTile: ", ""));
					settings.FoodPerTile = foodPerTile;
				}
				else if (line.StartsWith("BasicUpgradeFactor"))
				{
					float upgradeFactor = Single.Parse(line.Replace("BasicUpgradeFactor: ", ""));
					settings.BasicUpgradeFactor = upgradeFactor;
				}
				else if (line.StartsWith("UnitWeakenedFactor"))
				{
					float weakenedFactor = Single.Parse(line.Replace("UnitWeakenedFactor: ", ""));
					settings.WeakenedUnitFactor = weakenedFactor;
				}

				line = text.ReadLine();
			}
			return settings;
		}

		/// <summary>
		/// Parses the given string and returns a gold based condition predicate.
		/// </summary>
		/// <param name="conditionString">The string to parse.</param>
		private static PriorityOrderCondition ParseGoldCondition(string conditionString)
		{
			PriorityOrderCondition condition;
			conditionString = conditionString.Replace("gold", "").TrimEnd();
			if (conditionString.Contains(">"))
			{
				int value = Int32.Parse(conditionString.Replace(">", "").TrimEnd());
				condition = new PriorityOrderCondition((player) => player.Coins > value);
			}
			else if (conditionString.Contains("<"))
			{
				int value = Int32.Parse(conditionString.Replace("<", "").TrimEnd());
				condition = new PriorityOrderCondition((player) => player.Coins < value);
			}
			else
			{
				int value = Int32.Parse(conditionString.Replace("=", "").TrimEnd());
				condition = new PriorityOrderCondition((player) => player.Coins == value);
			}
			return condition;
		}

		/// <summary>
		/// Parses the given string and returns a sleeping based condition predicate.
		/// </summary>
		/// <param name="conditionString">The string to parse.</param>
		private static PriorityOrderCondition ParserSleepingCondition(string conditionString)
		{
			PriorityOrderCondition condition;
			conditionString = conditionString.Replace("sleeping", "").TrimEnd();
			if (conditionString.Contains(">"))
			{
				int value = Int32.Parse(conditionString.Replace(">", "").TrimEnd());
				condition = new PriorityOrderCondition((player) => player.SleepingUnits.Count > value);
			}
			else if (conditionString.Contains("<"))
			{
				int value = Int32.Parse(conditionString.Replace("<", "").TrimEnd());
				condition = new PriorityOrderCondition((player) => player.SleepingUnits.Count < value);
			}
			else
			{
				int value = Int32.Parse(conditionString.Replace("=", "").TrimEnd());
				condition = new PriorityOrderCondition((player) => player.SleepingUnits.Count == value);
			}
			return condition;
		}

		/// <summary>
		/// Parses the given string and returns an upgrade based condition predicate.
		/// </summary>
		/// <param name="conditionString">The string to parse.</param>
		private static PriorityOrderCondition ParseUpgradeCondition(string conditionString)
		{
			conditionString = conditionString.Replace("upgrade[", "");
			int rightBracketIndex = conditionString.IndexOf(']');
			int unitTier = Int32.Parse(conditionString.Substring(0, rightBracketIndex));
			conditionString = conditionString.Remove(0, rightBracketIndex + 1).TrimEnd();

			if (conditionString.Contains(">"))
			{
				int value = Int32.Parse(conditionString.Replace(">", ""));
				return new PriorityOrderCondition((player) => player.Race.Units[unitTier].Level > value);
			}
			else if (conditionString.Contains("<"))
			{
				int value = Int32.Parse(conditionString.Replace("<", ""));
				return new PriorityOrderCondition((player) => player.Race.Units[unitTier].Level < value);
			}
			else
			{
				int value = Int32.Parse(conditionString.Replace("=", ""));
				return new PriorityOrderCondition((player) => player.Race.Units[unitTier].Level == value);
			}
		}
	}
}
